package com.eyas.im.server.nio.handler;

import com.eyas.im.protocol.decoder.Decoder;
import com.eyas.im.protocol.encoder.Encoder;
import com.eyas.im.protocol.protocol.Protocol;
import com.eyas.im.server.ServerSocketHandler;
import com.eyas.im.server.TaskCompleteFuture;
import com.eyas.im.server.WriteCallbackFunction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.SocketAddress;

/**
 * 通信处理器，关于业务逻辑，同时作为ServerSocketIoEventHandler的适配器
 * 对应每一个双向TCP通道，都是线程安全的
 * @param <T>
 */
public abstract class AbstractNioServerSocketHandler<T extends Protocol<?>> extends ServerSocketIoEventHandler implements ServerSocketHandler<T> {
    private final static Logger logger = LoggerFactory.getLogger(AbstractNioServerSocketHandler.class);
    private Encoder<T> encoder;
    private Decoder<T> decoder;

    public AbstractNioServerSocketHandler(Encoder<T> encoder, Decoder<T> decoder,int bufferCapacity) {
        super(bufferCapacity);
        this.encoder = encoder;
        this.decoder = decoder;
    }

    public final void onDataReceived(byte[] bytes) {
        try {
            T result = this.decoder.decode(bytes);
            this.afterDecodeData(result);
        } catch (IOException e) {
            logger.error("解码协议数据失败",e);
        }
    }

    /**
     * 写数据，写操作不会阻塞调用线程的运行
     * @param sendData
     * @return
     * @throws IOException
     */
    public final TaskCompleteFuture write(T sendData, WriteCallbackFunction callbackFunction) throws IOException {
        byte[] bytes = this.encoder.encode(sendData);
        TaskCompleteFuture taskCompleteFuture = new TaskCompleteFuture(callbackFunction);
        this.pushWriteBytes(taskCompleteFuture,bytes);
        return taskCompleteFuture;
    }


    @Override
    public final void flush() {
        this.maskWrite();
    }

    @Override
    public abstract void afterAccept(SocketAddress socketAddress);

    @Override
    public abstract void beforeClose();

    @Override
    public final void shutdown() throws IOException {
        this.beforeClose();
        this.shutdown0();
    }

}
